package fag.core.geometry;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;


/**
 * Classe des polygones 2D. Le polygone est défini par un liste de sommet. Le dernier étant connecté au premier.
 * @author lumz
 */
public class Polygon2D extends AbstractPolygon implements Serializable {
	
	private static final long serialVersionUID = 3016565458103117916L;
	
	private Rectangle2D bounds = new Rectangle2D();
	private List<Vector2D> vertices = new ArrayList<Vector2D>();
	
	/**
	 * Constructeur avec initialisation.
	 * @param vertices Les sommets du polygone.
	 */
	public Polygon2D(List<Vector2D> vertices) {
		set(vertices);
	}
	
	@Override
	public Rectangle2D getBounds() {
		return bounds.clone();
	}
	
	@Override
	public Polygon2D clone() {
		return (Polygon2D) super.clone();
	}
	
	/**
	 * Getter des sommets du polygone.
	 * @return Une liste des sommets du polygone.
	 */
	public List<Vector2D> getVertices() {
		
		List<Vector2D> clonedVertices = new ArrayList<Vector2D>();
		
		for(Vector2D vertex : vertices)
			clonedVertices.add(vertex.clone());
		
		return clonedVertices;
	}
	
	/**
	 * Setter des sommets du polygone.
	 * @param vertices La liste des nouveaux sommets du polygone.
	 */
	public void set(List<Vector2D> vertices) {
		
		assert(vertices.size() > 3);
		
		for(Vector2D vertex : vertices)
			this.vertices.add(vertex.clone());
		
		updateBounds();
	}
	
	/**
	 * Assistance pour l'algorithme de détection GJK et EPA. Doit renvoyer le sommet le plus éloigné
	 * sur le vecteur d'assistance.
	 * @param d Le vecteur d'assistance.
	 * @return Le sommet le plus éloigné sur le vecteur d'assistance.
	 */
	public Vector2D supportMapping(Vector2D d) {
		
		Vector2D result = new Vector2D();
		
		if(vertices.size() > 0) {
			
			result = vertices.get(0);
			double max = d.dot(result);
			
			for(int i = 1; i < vertices.size(); ++i) {
				
				Vector2D candidate = vertices.get(i);
				
				if(d.dot(candidate) > max) {
					max = d.dot(candidate);
					result = candidate;
				}
			}
		}
		
		return result;
	}
	
	@Override
	public String toString() {
		
		String result = new String() + "Polygon2D(";
		
		for(int i = 0; i < vertices.size(); ++i) {
			
			if(i > 0)
				result += "; ";
			
			Vector2D vertex = vertices.get(i);
			result += vertex.x + ", " + vertex.y;
		}
		
		return result;
	}
	
	/**
	 * Précalcule le volume englobant du polygone.
	 */
	protected void updateBounds() {
		
		double minX = 0;
		double minY = 0;
		double maxX = 0;
		double maxY = 0;
		
		// Initialisation avec le premier sommet du polygone
		if(vertices.size() > 0) {
			Vector2D initialVertex = vertices.get(0);
			minX = initialVertex.x;
			minY = initialVertex.y;
			maxX = minX;
			maxY = minY;
		}
		
		// Elargissement aux sommets du polygone
		for(Vector2D vertex : vertices) {
			
			if(minX > vertex.x)
				minX = vertex.x;
			
			if(maxX < vertex.x)
				maxX = vertex.x;
			
			if(minY > vertex.y)
				minY = vertex.y;
		
			if(maxY < vertex.y)
				maxY = vertex.y;
			
		}
		
		bounds.set(minX, minY, maxX - minX, maxY - minY);
	}
}
